<script lang="ts" setup>
import Guacamole from 'guacamole-common-js'
import { onMounted, reactive, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { getCodeDetail, statusCode } from '../../../utils/guacd_code'
import { getQueryVariable } from '../../../utils/common'

const desktopObj = {
  client: undefined,
  layer: undefined,
  state: 0,
  sink: undefined
}

onMounted(() => {
  const sessionId = getQueryVariable('a')
  // // 远程桌面画布的大小
  const width = document.body.clientWidth - 1
  const height = document.body.clientHeight
  console.log(width, height, sessionId)
  wsHandshake('1561649906957946880')
  // // 监听窗口大小变化，执行窗口重绘操作
  // window.addEventListener('resize', onWindowResize)
  // window.onfocus = onWindowFocus
})

const websocketPath = import.meta.env.VITE_WEBSOCKET_PATH

const wsHandshake = (sessionId:string) => {
  const width = document.body.clientWidth - 1
  const height = document.body.clientHeight
  const params = 'width=' + width + '&height=' + height + '&session_id=' + sessionId + '&dpi=' + 90
  const tunnel = new Guacamole.WebSocketTunnel(websocketPath + '/gua/tunnel-monitor')
  tunnel.onerror = onTunnelError
  // 通道状态改变时的回调函数
  tunnel.onstatechange = onTunnelStateChange
  // 创建桌面客户端
  desktopObj.client = new Guacamole.Client(tunnel)
  // 解析自定义指令，这行代码必须放到  new Guacamole.Client(tunnel) 代码之后
  const _oninstruction = tunnel.oninstruction
  tunnel.oninstruction = function (opcode, parameters) {
    onTunnelInstruction(opcode, parameters)
    if (_oninstruction) {
      _oninstruction(opcode, parameters)
    }
  }
  // todo 设置虚拟机剪贴板内容

  desktopObj.client.onerror = onClientError
  // 处理客户端的状态变化事件
  desktopObj.client.onstatechange = onClientStateChange
  // 客户端连接发生错误的时候的回调函数
  desktopObj.client.onerror = function (status) {
    console.log('error', status)
  }
  const display = document.getElementById('display')
  desktopObj.layer = desktopObj.client.getDisplay()
  const element = desktopObj.client.getDisplay().getElement()
  display.appendChild(element)
  desktopObj.client.connect(params)
  // 页面关闭时销毁客户端对象
  window.onunload = function () {
    desktopObj.client.disconnect()
  }

  // mouse
  const mouse = new Guacamole.Mouse(element)
  mouse.onmousedown =
      mouse.onmouseup =
          mouse.onmousemove = function (mouseState:any) {
            const ms = new Guacamole.Mouse.State(
              mouseState.x / desktopObj.layer.getScale(),
              mouseState.y / desktopObj.layer.getScale(),
              mouseState.left,
              mouseState.middle,
              mouseState.right,
              mouseState.up,
              mouseState.down
            )
            desktopObj.client.sendMouseState(ms)
          }
  // sink
  desktopObj.sink = new Guacamole.InputSink()
  display.appendChild(sink.getElement())
  desktopObj.sink.focus()

  // Keyboard
  const keyboard = new Guacamole.Keyboard(desktopObj.sink.getElement())
  keyboard.onkeydown = onKeyDown
  keyboard.onkeyup = onKeyUp
}

const onClientStateChange = (state) => {
  console.log('onClientStateChange', state)
  const STATE_IDLE = 0
  const STATE_CONNECTING = 1
  const STATE_WAITING = 2
  const STATE_CONNECTED = 3
  const STATE_DISCONNECTING = 4
  const STATE_DISCONNECTED = 5
  switch (state) {
    case STATE_IDLE:
      console.log('STATE_CONNECTED')
      return
    case STATE_CONNECTING:
      console.log('STATE_CONNECTING')
      return
    case STATE_WAITING:
      console.log('STATE_WAITING')
      return
    case STATE_CONNECTED:
      console.log('客户端已连接')
      desktopObj.state = state
      return
    case STATE_DISCONNECTING:
      console.log('客户端正在关闭连接')
      return
    case STATE_DISCONNECTED:
      console.log('客户端连接已关闭')
  }
}

const onTunnelError = (state:any) => {
  console.log('onTunnelError', state)
  const code = state.code
  console.error('通道错误', getCodeDetail(code))
  ElMessage.error(getCodeDetail(code))
  const msg = statusCode[code]
  if (msg) {
    console.log(msg)
  }
}

const onClientError = (state:any) => {
  const code = state.code
  console.error('客户端错误', getCodeDetail(code))
  if (statusCode[code]) {
    console.log(statusCode[code])
  }
}

const onTunnelStateChange = (state:number) => {
  switch (state) {
    case Guacamole.Tunnel.State.CONNECTING:
      ElMessage({
        message: '建立连接通道...',
        type: 'warning'
      })
      return
    case Guacamole.Tunnel.State.OPEN:
      ElMessage({
        message: '通道已打开。',
        type: 'warning'
      })
      return
    case Guacamole.Tunnel.State.CLOSED:
      ElMessage({
        message: '连接已关闭。',
        type: 'warning'
      })
      return
    case Guacamole.Tunnel.State.UNSTABLE:
      ElMessage({
        message: '连接不稳定。',
        type: 'warning'
      })
  }
}

const onTunnelInstruction = (opcode, parameters) => {
  if (opcode === 'ready') {
    console.log('参数就绪，准备开始连接应用服务器')
    return
  }
  if (opcode === 'select') {
    console.log('账号密码验证成功，准备打开远程画面')
    return
  }
  if (opcode === 'vesystem') {
    console.log('vesystem', opcode, parameters)
    return
  }
  if (opcode === 'disconnect') {
    console.log('连接销毁，画面关闭')
    return
  }
  if (opcode === 'error') {
    console.error('指令', opcode, '参数', parameters)
    if (parameters.indexOf('Authentication failure (invalid credentials') > 0) {
      console.log('认证失败 (无效凭证)')
      return
    }
    if (parameters.indexOf('Connection failed (server unreachable') > 0) {
      console.log('guacd 无法连接到应用服务器')
      return
    }
    desktopObj.client.disconnect()
  }
}

const onKeyUp = (keySym) => {
  desktopObj.client.sendKeyEvent(0, keySym)
}
const onKeyDown = (keySym) => {
  console.log(keySym)
  desktopObj.client.sendKeyEvent(1, keySym)
  if (keySym === 65288) {
    return false
  }
}
</script>

<template>
  <div>监控页面</div>
  <div id="display" class="desktop-div"></div>
</template>

<style lang="scss" scoped>
.desktop-div{
  width: 100%;
  height: 100%;
}
</style>
